์ ์ธ๊ณ์ ์ผ๋ก ๊ฒฌ๊ณ ํ๊ณ ์ ๋ขฐํ ์ ์๋ ๋น๋๊ธฐ ์ ํ๋ฆฌ์ผ์ด์ ๊ตฌ์ถ์ ์ํ ๊ณ ๊ธ ์ค๋ฅ ์ฒ๋ฆฌ ๊ธฐ์ ์ ๋ค๋ฃจ๋ AsyncIO ๊ธฐ๋ฐ ํ์ด์ฌ ์ฝ๋ฃจํด ๋๋ฒ๊น ์ข ํฉ ๊ฐ์ด๋์ ๋๋ค.
AsyncIO ๋ง์คํฐํ๊ธฐ: ๊ธ๋ก๋ฒ ๊ฐ๋ฐ์๋ฅผ ์ํ ํ์ด์ฌ ์ฝ๋ฃจํด ๋๋ฒ๊น ๋ฐ ์ค๋ฅ ์ฒ๋ฆฌ ์ ๋ต
ํ์ด์ฌ์ asyncio๋ฅผ ์ฌ์ฉํ ๋น๋๊ธฐ ํ๋ก๊ทธ๋๋ฐ์ ๊ณ ์ฑ๋ฅ์ ํ์ฅ ๊ฐ๋ฅํ ์ ํ๋ฆฌ์ผ์ด์
์ ๊ตฌ์ถํ๋ ๋ฐ ํต์ฌ์ ์ธ ์์๊ฐ ๋์์ต๋๋ค. ์น ์๋ฒ์ ๋ฐ์ดํฐ ํ์ดํ๋ผ์ธ๋ถํฐ IoT ๊ธฐ๊ธฐ ๋ฐ ๋ง์ดํฌ๋ก์๋น์ค์ ์ด๋ฅด๊ธฐ๊น์ง, asyncio๋ ๊ฐ๋ฐ์๋ค์ด I/O ๋ฐ์ด๋ ์์
์ ๋๋ผ์ด ํจ์จ์ฑ์ผ๋ก ์ฒ๋ฆฌํ ์ ์๊ฒ ํด์ค๋๋ค. ๊ทธ๋ฌ๋ ๋น๋๊ธฐ ์ฝ๋์ ๋ด์ฌ๋ ๋ณต์ก์ฑ์ ๋
ํนํ ๋๋ฒ๊น
๋ฌธ์ ๋ฅผ ์ผ๊ธฐํ ์ ์์ต๋๋ค. ์ด ์ข
ํฉ ๊ฐ์ด๋๋ ๊ธ๋ก๋ฒ ๊ฐ๋ฐ์๋ค์ ์ํด ํ์ด์ฌ ์ฝ๋ฃจํด์ ๋๋ฒ๊น
ํ๊ณ asyncio ์ ํ๋ฆฌ์ผ์ด์
๋ด์์ ๊ฒฌ๊ณ ํ ์ค๋ฅ ์ฒ๋ฆฌ๋ฅผ ๊ตฌํํ๋ ํจ๊ณผ์ ์ธ ์ ๋ต์ ๊น์ด ์๊ฒ ๋ค๋ฃน๋๋ค.
๋น๋๊ธฐ ํ๊ฒฝ: ์ฝ๋ฃจํด ๋๋ฒ๊น ์ด ์ค์ํ ์ด์
์ ํต์ ์ธ ๋๊ธฐ ํ๋ก๊ทธ๋๋ฐ์ ์ ํ์ ์ธ ์คํ ๊ฒฝ๋ก๋ฅผ ๋ฐ๋ฅด๋ฏ๋ก ์ค๋ฅ๋ฅผ ์ถ์ ํ๊ธฐ๊ฐ ๋น๊ต์ ๊ฐ๋จํฉ๋๋ค. ๋ฐ๋ฉด, ๋น๋๊ธฐ ํ๋ก๊ทธ๋๋ฐ์ ์ฌ๋ฌ ์์ ์ ๋์ ์คํ์ ํฌํจํ๋ฉฐ, ์ข ์ข ์ด๋ฒคํธ ๋ฃจํ์ ์ ์ด๊ถ์ ๋๊ฒจ์ค๋๋ค. ์ด๋ฌํ ๋์์ฑ์ ํ์ค ๋๋ฒ๊น ๊ธฐ์ ๋ก๋ ์ฐพ์๋ด๊ธฐ ์ด๋ ค์ด ๋ฏธ๋ฌํ ๋ฒ๊ทธ๋ก ์ด์ด์ง ์ ์์ต๋๋ค. ๋ ์ด์ค ์ปจ๋์ , ๋ฐ๋๋ฝ, ์์์น ๋ชปํ ์์ ์ทจ์์ ๊ฐ์ ๋ฌธ์ ๋ค์ด ๋ ๋น๋ฒํ๊ฒ ๋ฐ์ํฉ๋๋ค.
์๋ก ๋ค๋ฅธ ์๊ฐ๋์์ ์์
ํ๊ณ ๊ตญ์ ํ๋ก์ ํธ์์ ํ์
ํ๋ ๊ฐ๋ฐ์๋ค์๊ฒ asyncio ๋๋ฒ๊น
๋ฐ ์ค๋ฅ ์ฒ๋ฆฌ์ ๋ํ ํ์คํ ์ดํด๋ ๋งค์ฐ ์ค์ํฉ๋๋ค. ์ด๋ ์ ํ๋ฆฌ์ผ์ด์
์ด ํ๊ฒฝ, ์ฌ์ฉ์ ์์น ๋๋ ๋คํธ์ํฌ ์กฐ๊ฑด์ ๊ด๊ณ์์ด ์์ ์ ์ผ๋ก ์๋ํ๋๋ก ๋ณด์ฅํฉ๋๋ค. ์ด ๊ฐ์ด๋๋ ์ฌ๋ฌ๋ถ์ด ์ด๋ฌํ ๋ณต์ก์ฑ์ ํจ๊ณผ์ ์ผ๋ก ํด๊ฒฐํ ์ ์๋ ์ง์๊ณผ ๋๊ตฌ๋ฅผ ๊ฐ์ถ๋๋ก ๋๋ ๊ฒ์ ๋ชฉํ๋ก ํฉ๋๋ค.
์ฝ๋ฃจํด ์คํ๊ณผ ์ด๋ฒคํธ ๋ฃจํ ์ดํดํ๊ธฐ
๋๋ฒ๊น
๊ธฐ์ ์ ์ดํด๋ณด๊ธฐ ์ ์, ์ฝ๋ฃจํด์ด asyncio ์ด๋ฒคํธ ๋ฃจํ์ ์ด๋ป๊ฒ ์ํธ์์ฉํ๋์ง ํ์
ํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค. ์ฝ๋ฃจํด์ ์คํ์ ์ผ์ ์ค์งํ๋ค๊ฐ ๋์ค์ ์ฌ๊ฐํ ์ ์๋ ํน๋ณํ ์ ํ์ ํจ์์
๋๋ค. asyncio ์ด๋ฒคํธ ๋ฃจํ๋ ๋น๋๊ธฐ ์คํ์ ์ฌ์ฅ๋ถ๋ก, ์ฝ๋ฃจํด์ ์คํ์ ๊ด๋ฆฌํ๊ณ ์ค์ผ์ค๋งํ๋ฉฐ, ์์
์ด ์ค๋น๋๋ฉด ๊นจ์์ค๋๋ค.
๊ธฐ์ตํด์ผ ํ ์ฃผ์ ๊ฐ๋ :
async def: ์ฝ๋ฃจํด ํจ์๋ฅผ ์ ์ํฉ๋๋ค.await: awaitable์ด ์๋ฃ๋ ๋๊น์ง ์ฝ๋ฃจํด์ ์คํ์ ์ผ์ ์ค์งํฉ๋๋ค. ์ด ์ง์ ์์ ์ ์ด๊ถ์ด ์ด๋ฒคํธ ๋ฃจํ๋ก ๋์ด๊ฐ๋๋ค.- Tasks:
asyncio๋ ์ฝ๋ฃจํด์Task๊ฐ์ฒด๋ก ๊ฐ์ธ ์คํ์ ๊ด๋ฆฌํฉ๋๋ค. - Event Loop: ํ์คํฌ์ ์ฝ๋ฐฑ์ ์คํํ๋ ์ค์ ์ค์ผ์คํธ๋ ์ดํฐ์ ๋๋ค.
await ๋ฌธ์ ๋ง๋๋ฉด ์ฝ๋ฃจํด์ ์ ์ด๊ถ์ ํฌ๊ธฐํฉ๋๋ค. ๋ง์ฝ ๋๊ธฐ ์ค์ธ ์์
์ด I/O ๋ฐ์ด๋(์: ๋คํธ์ํฌ ์์ฒญ, ํ์ผ ์ฝ๊ธฐ)๋ผ๋ฉด, ์ด๋ฒคํธ ๋ฃจํ๋ ๋ค๋ฅธ ์ค๋น๋ ํ์คํฌ๋ก ์ ํํ์ฌ ๋์์ฑ์ ๋ฌ์ฑํ ์ ์์ต๋๋ค. ๋๋ฒ๊น
์ ์ข
์ข
์ฝ๋ฃจํด์ด ์ธ์ , ์ ์๋ณดํ๊ณ , ์ด๋ป๊ฒ ์ฌ๊ฐ๋๋์ง๋ฅผ ์ดํดํ๋ ๊ณผ์ ์ ํฌํจํฉ๋๋ค.
์ผ๋ฐ์ ์ธ ์ฝ๋ฃจํด์ ํจ์ ๊ณผ ์ค๋ฅ ์๋๋ฆฌ์ค
asyncio ์ฝ๋ฃจํด์ผ๋ก ์์
ํ ๋ ๋ช ๊ฐ์ง ์ผ๋ฐ์ ์ธ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค:
- ์ฒ๋ฆฌ๋์ง ์์ ์์ธ: ์ฝ๋ฃจํด ๋ด์์ ๋ฐ์ํ ์์ธ๋ ์กํ์ง ์์ผ๋ฉด ์์์น ๋ชปํ ๊ณณ์ผ๋ก ์ ํ๋ ์ ์์ต๋๋ค.
- ์์
์ทจ์: ํ์คํฌ๋ ์ทจ์๋ ์ ์์ผ๋ฉฐ, ์ด๋ก ์ธํด
asyncio.CancelledError๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค. ์ด๋ ์ฐ์ํ๊ฒ ์ฒ๋ฆฌ๋์ด์ผ ํฉ๋๋ค. - ๋ฐ๋๋ฝ ๋ฐ ๊ธฐ์ ์ํ: ๋๊ธฐํ ํ๋ฆฌ๋ฏธํฐ๋ธ์ ๋ถ์ ์ ํ ์ฌ์ฉ์ด๋ ๋ฆฌ์์ค ๊ฒฝ์์ ํ์คํฌ๊ฐ ๋ฌดํ์ ๋๊ธฐํ๊ฒ ๋ง๋ค ์ ์์ต๋๋ค.
- ๋ ์ด์ค ์ปจ๋์ : ์ฌ๋ฌ ์ฝ๋ฃจํด์ด ์ ์ ํ ๋๊ธฐํ ์์ด ๊ณต์ ๋ฆฌ์์ค์ ๋์์ ์ ๊ทผํ๊ณ ์์ ํ๋ ๊ฒฝ์ฐ์ ๋๋ค.
- ์ฝ๋ฐฑ ํฌ: ์ต์
asyncioํจํด์์๋ ๋ ์ผ๋ฐ์ ์ด์ง๋ง, ๋ณต์กํ ์ฝ๋ฐฑ ์ฒด์ธ์ ์ฌ์ ํ ๊ด๋ฆฌํ๊ณ ๋๋ฒ๊น ํ๊ธฐ ์ด๋ ค์ธ ์ ์์ต๋๋ค. - ๋ธ๋กํน ์์ : ์ฝ๋ฃจํด ๋ด์์ ๋๊ธฐ์ ์ด๊ณ ๋ธ๋กํน I/O ์์ ์ ํธ์ถํ๋ฉด ์ ์ฒด ์ด๋ฒคํธ ๋ฃจํ๊ฐ ๋ฉ์ถ์ด ๋น๋๊ธฐ ํ๋ก๊ทธ๋๋ฐ์ ์ด์ ์ ๋ฌดํจํํ ์ ์์ต๋๋ค.
AsyncIO์ ํ์ ์ค๋ฅ ์ฒ๋ฆฌ ์ ๋ต
๊ฒฌ๊ณ ํ ์ค๋ฅ ์ฒ๋ฆฌ๋ ์ ํ๋ฆฌ์ผ์ด์
์คํจ์ ๋ํ ์ฒซ ๋ฒ์งธ ๋ฐฉ์ด์ ์
๋๋ค. asyncio๋ ํ์ด์ฌ์ ํ์ค ์์ธ ์ฒ๋ฆฌ ๋ฉ์ปค๋์ฆ์ ํ์ฉํ์ง๋ง, ๋น๋๊ธฐ์ ์ธ ๋ฏธ๋ฌํ ์ฐจ์ด๊ฐ ์์ต๋๋ค.
1. try...except...finally์ ํ
์์ธ ์ฒ๋ฆฌ๋ฅผ ์ํ ๊ธฐ๋ณธ์ ์ธ ํ์ด์ฌ ๊ตฌ๋ฌธ์ ์ฝ๋ฃจํด์ ์ง์ ์ ์ฉ๋ฉ๋๋ค. ์ ์ฌ์ ์ผ๋ก ๋ฌธ์ ๊ฐ ๋ ์ ์๋ await ํธ์ถ์ด๋ ๋น๋๊ธฐ ์ฝ๋ ๋ธ๋ก์ try ๋ธ๋ก์ผ๋ก ๊ฐ์ธ์ธ์.
import asyncio
async def fetch_data(url):
print(f"Fetching data from {url}...")
await asyncio.sleep(1) # Simulate network delay
if "error" in url:
raise ValueError(f"Failed to fetch from {url}")
return f"Data from {url}"
async def process_urls(urls):
tasks = []
for url in urls:
tasks.append(asyncio.create_task(fetch_data(url)))
results = []
for task in asyncio.as_completed(tasks):
try:
result = await task
results.append(result)
print(f"Successfully processed: {result}")
except ValueError as e:
print(f"Error processing URL: {e}")
except Exception as e:
print(f"An unexpected error occurred: {e}")
finally:
# Code here runs whether an exception occurred or not
print("Finished processing one task.")
return results
async def main():
urls = [
"http://example.com/data1",
"http://example.com/error_source",
"http://example.com/data2"
]
await process_urls(urls)
if __name__ == "__main__":
asyncio.run(main())
์ค๋ช :
- ์ฌ๋ฌ
fetch_data์ฝ๋ฃจํด์ ์ค์ผ์ค๋งํ๊ธฐ ์ํดasyncio.create_task๋ฅผ ์ฌ์ฉํฉ๋๋ค. asyncio.as_completed๋ ํ์คํฌ๊ฐ ๋๋๋ ๋๋ก ๋ฐํํ์ฌ ๊ฒฐ๊ณผ๋ ์ค๋ฅ๋ฅผ ์ ์ํ๊ฒ ์ฒ๋ฆฌํ ์ ์๊ฒ ํฉ๋๋ค.- ๊ฐ
await task๋try...except๋ธ๋ก์ผ๋ก ๊ฐ์ธ์ ธ, ์๋ฎฌ๋ ์ด์ ๋ API์์ ๋ฐ์ํ ํน์ ValueError์์ธ๋ฟ๋ง ์๋๋ผ ๋ค๋ฅธ ์์์น ๋ชปํ ์์ธ๋ ์ก์ต๋๋ค. finally๋ธ๋ก์ ๋ฆฌ์์ค ํด์ ๋ ๋ก๊น ๊ณผ ๊ฐ์ด ์์ธ ๋ฐ์ ์ฌ๋ถ์ ์๊ด์์ด ํญ์ ์คํ๋์ด์ผ ํ๋ ์ ๋ฆฌ ์์ ์ ์ ์ฉํฉ๋๋ค.
2. asyncio.CancelledError ์ฒ๋ฆฌํ๊ธฐ
asyncio์ ํ์คํฌ๋ ์ทจ์๋ ์ ์์ต๋๋ค. ์ด๋ ์ฅ๊ธฐ ์คํ ์์
์ ๊ด๋ฆฌํ๊ฑฐ๋ ์ ํ๋ฆฌ์ผ์ด์
์ ์ฐ์ํ๊ฒ ์ข
๋ฃํ๋ ๋ฐ ์ค์ํฉ๋๋ค. ํ์คํฌ๊ฐ ์ทจ์๋๋ฉด, ํ์คํฌ๊ฐ ๋ง์ง๋ง์ผ๋ก ์ ์ด๊ถ์ ์๋ณดํ ์ง์ (์ฆ, await)์์ asyncio.CancelledError๊ฐ ๋ฐ์ํฉ๋๋ค. ํ์ํ ์ ๋ฆฌ๋ฅผ ์ํํ๊ธฐ ์ํด ์ด ์ค๋ฅ๋ฅผ ์ก๋ ๊ฒ์ด ํ์์ ์
๋๋ค.
import asyncio
async def cancellable_task():
try:
for i in range(5):
print(f"Task step {i}")
await asyncio.sleep(1)
print("Task completed normally.")
except asyncio.CancelledError:
print("Task was cancelled! Performing cleanup...")
# Simulate cleanup operations
await asyncio.sleep(0.5)
print("Cleanup finished.")
raise # Re-raise CancelledError if required by convention
finally:
print("This finally block always runs.")
async def main():
task = asyncio.create_task(cancellable_task())
await asyncio.sleep(2.5) # Let the task run for a bit
print("Cancelling the task...")
task.cancel()
try:
await task # Wait for the task to acknowledge cancellation
except asyncio.CancelledError:
print("Main caught CancelledError after task cancellation.")
if __name__ == "__main__":
asyncio.run(main())
์ค๋ช :
cancellable_task์๋try...except asyncio.CancelledError๋ธ๋ก์ด ์์ต๋๋ค.except๋ธ๋ก ์์์ ์ ๋ฆฌ ์์ ์ ์ํํฉ๋๋ค.- ์ค์ํ ๊ฒ์, ์ ๋ฆฌ ํ ์ข
์ข
CancelledError๋ฅผ ๋ค์ ๋ฐ์์ํจ๋ค๋ ์ ์ ๋๋ค. ์ด๋ ํธ์ถ์์๊ฒ ํ์คํฌ๊ฐ ์ค์ ๋ก ์ทจ์๋์์์ ์๋ฆฌ๋ ์ ํธ์ ๋๋ค. ๋ค์ ๋ฐ์์ํค์ง ์๊ณ ์ต์ ํ๋ฉด, ํธ์ถ์๋ ํ์คํฌ๊ฐ ์ฑ๊ณต์ ์ผ๋ก ์๋ฃ๋์๋ค๊ณ ์ฐฉ๊ฐํ ์ ์์ต๋๋ค. mainํจ์๋ ํ์คํฌ๋ฅผ ์ทจ์ํ๊ณawaitํ๋ ๋ฐฉ๋ฒ์ ๋ณด์ฌ์ค๋๋ค. ์ดawait task๋ ํ์คํฌ๊ฐ ์ทจ์๋๊ณ ์์ธ๋ฅผ ๋ค์ ๋ฐ์์์ผฐ๋ค๋ฉด ํธ์ถ์์์CancelledError๋ฅผ ๋ฐ์์ํต๋๋ค.
3. ์์ธ ์ฒ๋ฆฌ๋ฅผ ํฌํจํ asyncio.gather ์ฌ์ฉํ๊ธฐ
asyncio.gather๋ ์ฌ๋ฌ awaitable์ ๋์์ ์คํํ๊ณ ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ๋ชจ์ผ๋ ๋ฐ ์ฌ์ฉ๋ฉ๋๋ค. ๊ธฐ๋ณธ์ ์ผ๋ก, ๋ง์ฝ ์ด๋ค awaitable์ด ์์ธ๋ฅผ ๋ฐ์์ํค๋ฉด, gather๋ ์ฆ์ ๋ง์ฃผ์น ์ฒซ ๋ฒ์งธ ์์ธ๋ฅผ ์ ํํ๊ณ ๋๋จธ์ง awaitable๋ค์ ์ทจ์ํฉ๋๋ค.
gather ํธ์ถ ๋ด์์ ๊ฐ๋ณ ์ฝ๋ฃจํด์ ์์ธ๋ฅผ ์ฒ๋ฆฌํ๋ ค๋ฉด return_exceptions=True ์ธ์๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
import asyncio
async def successful_operation(delay):
await asyncio.sleep(delay)
return f"Success after {delay}s"
async def failing_operation(delay):
await asyncio.sleep(delay)
raise RuntimeError(f"Failed after {delay}s")
async def main():
results = await asyncio.gather(
successful_operation(1),
failing_operation(0.5),
successful_operation(1.5),
return_exceptions=True
)
print("Results from gather:")
for i, result in enumerate(results):
if isinstance(result, Exception):
print(f"Task {i}: Failed with exception: {result}")
else:
print(f"Task {i}: Succeeded with result: {result}")
if __name__ == "__main__":
asyncio.run(main())
์ค๋ช :
return_exceptions=True๋ฅผ ์ฌ์ฉํ๋ฉด, ์์ธ๊ฐ ๋ฐ์ํด๋gather๊ฐ ๋ฉ์ถ์ง ์์ต๋๋ค. ๋์ , ์์ธ ๊ฐ์ฒด ์์ฒด๊ฐ ๊ฒฐ๊ณผ ๋ฆฌ์คํธ์ ํด๋น ์์น์ ๋ฐฐ์น๋ฉ๋๋ค.- ๊ทธ๋ฐ ๋ค์ ์ฝ๋๋ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ๋ณตํ๋ฉด์ ๊ฐ ํญ๋ชฉ์ ์ ํ์ ํ์ธํฉ๋๋ค. ๋ง์ฝ
Exception์ด๋ผ๋ฉด, ํด๋น ํ์คํฌ๊ฐ ์คํจํ๋ค๋ ์๋ฏธ์ ๋๋ค.
4. ๋ฆฌ์์ค ๊ด๋ฆฌ๋ฅผ ์ํ ์ปจํ ์คํธ ๋งค๋์
์ปจํ
์คํธ ๋งค๋์ (async with ์ฌ์ฉ)๋ ์ค๋ฅ๊ฐ ๋ฐ์ํ๋๋ผ๋ ๋ฆฌ์์ค๊ฐ ์ ์ ํ๊ฒ ํ๋๋๊ณ ํด์ ๋๋๋ก ๋ณด์ฅํ๋ ํ๋ฅญํ ๋ฐฉ๋ฒ์
๋๋ค. ์ด๋ ๋คํธ์ํฌ ์ฐ๊ฒฐ, ํ์ผ ํธ๋ค ๋๋ ๋ฝ์ ํนํ ์ ์ฉํฉ๋๋ค.
import asyncio
class AsyncResource:
def __init__(self, name):
self.name = name
self.acquired = False
async def __aenter__(self):
print(f"Acquiring resource: {self.name}")
await asyncio.sleep(0.2) # Simulate acquisition time
self.acquired = True
return self
async def __aexit__(self, exc_type, exc_val, exc_tb):
print(f"Releasing resource: {self.name}")
await asyncio.sleep(0.2) # Simulate release time
self.acquired = False
if exc_type:
print(f"An exception occurred within the context: {exc_type.__name__}: {exc_val}")
# Return True to suppress the exception, False or None to propagate
return False # Propagate exceptions by default
async def use_resource(name):
try:
async with AsyncResource(name) as resource:
print(f"Using resource {resource.name}...")
await asyncio.sleep(1)
if name == "flaky_resource":
raise RuntimeError("Simulated error during resource use")
print(f"Finished using resource {resource.name}.")
except RuntimeError as e:
print(f"Caught exception outside context manager: {e}")
async def main():
await use_resource("stable_resource")
print("---")
await use_resource("flaky_resource")
if __name__ == "__main__":
asyncio.run(main())
์ค๋ช :
AsyncResourceํด๋์ค๋ ๋น๋๊ธฐ ์ปจํ ์คํธ ๊ด๋ฆฌ๋ฅผ ์ํด__aenter__์__aexit__๋ฅผ ๊ตฌํํฉ๋๋ค.__aenter__๋async with๋ธ๋ก์ ์ง์ ํ ๋ ํธ์ถ๋๊ณ ,__aexit__๋ ์์ธ ๋ฐ์ ์ฌ๋ถ์ ๊ด๊ณ์์ด ๋ธ๋ก์ ๋น ์ ธ๋๊ฐ ๋ ํธ์ถ๋ฉ๋๋ค.__aexit__์ ํ๋ผ๋ฏธํฐ(exc_type,exc_val,exc_tb)๋ ๋ฐ์ํ ์์ธ์ ๋ํ ์ ๋ณด๋ฅผ ์ ๊ณตํฉ๋๋ค.__aexit__์์True๋ฅผ ๋ฐํํ๋ฉด ์์ธ๊ฐ ์ต์ ๋๊ณ ,False๋None์ ๋ฐํํ๋ฉด ์์ธ๊ฐ ์ ํ๋ฉ๋๋ค.
ํจ๊ณผ์ ์ธ ์ฝ๋ฃจํด ๋๋ฒ๊น
๋น๋๊ธฐ ์ฝ๋๋ฅผ ๋๋ฒ๊น ํ๋ ๊ฒ์ ๋๊ธฐ ์ฝ๋๋ฅผ ๋๋ฒ๊น ํ๋ ๊ฒ๊ณผ๋ ๋ค๋ฅธ ์ฌ๊ณ ๋ฐฉ์๊ณผ ๋๊ตฌ ์ธํธ๋ฅผ ํ์๋ก ํฉ๋๋ค.
1. ๋ก๊น ์ ์ ๋ต์ ์ฌ์ฉ
๋ก๊น
์ ๋น๋๊ธฐ ์ ํ๋ฆฌ์ผ์ด์
์ ํ๋ฆ์ ์ดํดํ๋ ๋ฐ ํ์์ ์
๋๋ค. ์ด๋ฅผ ํตํด ์คํ์ ์ค๋จํ์ง ์๊ณ ์ด๋ฒคํธ, ๋ณ์ ์ํ ๋ฐ ์์ธ๋ฅผ ์ถ์ ํ ์ ์์ต๋๋ค. ํ์ด์ฌ์ ๋ด์ฅ logging ๋ชจ๋์ ์ฌ์ฉํ์ธ์.
import asyncio
import logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
async def log_task(name, delay):
logging.info(f"Task '{name}' started.")
try:
await asyncio.sleep(delay)
if delay > 1:
raise ValueError(f"Simulated error for '{name}' due to long delay.")
logging.info(f"Task '{name}' completed successfully after {delay}s.")
except asyncio.CancelledError:
logging.warning(f"Task '{name}' was cancelled.")
raise
except Exception as e:
logging.error(f"Task '{name}' encountered an error: {e}")
raise
async def main():
tasks = [
asyncio.create_task(log_task("Task A", 1)),
asyncio.create_task(log_task("Task B", 2)),
asyncio.create_task(log_task("Task C", 0.5))
]
await asyncio.gather(*tasks, return_exceptions=True)
logging.info("All tasks have finished.")
if __name__ == "__main__":
asyncio.run(main())
AsyncIO์์์ ๋ก๊น ํ:
- ํ์์คํฌํ: ์ฌ๋ฌ ํ์คํฌ์ ๊ฑธ์น ์ด๋ฒคํธ๋ฅผ ์ฐ๊ด์ํค๊ณ ํ์ด๋ฐ์ ์ดํดํ๋ ๋ฐ ํ์์ ์ ๋๋ค.
- ํ์คํฌ ์๋ณ: ์์ ์ ์ํํ๋ ํ์คํฌ์ ์ด๋ฆ์ด๋ ID๋ฅผ ๋ก๊ทธ์ ๋จ๊ธฐ์ธ์.
- ์๊ด ๊ด๊ณ ID: ๋ถ์ฐ ์์คํ ์ ๊ฒฝ์ฐ, ์ฌ๋ฌ ์๋น์ค์ ํ์คํฌ์ ๊ฑธ์น ์์ฒญ์ ์ถ์ ํ๊ธฐ ์ํด ์๊ด ๊ด๊ณ ID๋ฅผ ์ฌ์ฉํ์ธ์.
- ๊ตฌ์กฐํ๋ ๋ก๊น
: ๋ ์ฒด๊ณ์ ์ด๊ณ ์กฐํ ๊ฐ๋ฅํ ๋ก๊ทธ ๋ฐ์ดํฐ๋ฅผ ์ํด
structlog์ ๊ฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ฌ์ฉ์ ๊ณ ๋ คํ์ธ์. ์ด๋ ๋ค์ํ ํ๊ฒฝ์ ๋ก๊ทธ๋ฅผ ๋ถ์ํ๋ ๊ตญ์ ํ์๊ฒ ์ ์ฉํฉ๋๋ค.
2. ํ์ค ๋๋ฒ๊ฑฐ ์ฌ์ฉํ๊ธฐ (์ฃผ์์ ๊ณผ ํจ๊ป)
pdb์ ๊ฐ์ ํ์ค ํ์ด์ฌ ๋๋ฒ๊ฑฐ(๋๋ IDE ๋๋ฒ๊ฑฐ)๋ฅผ ์ฌ์ฉํ ์ ์์ง๋ง, ๋น๋๊ธฐ ์ปจํ
์คํธ์์๋ ์ ์คํ ์ฒ๋ฆฌ๊ฐ ํ์ํฉ๋๋ค. ๋๋ฒ๊ฑฐ๊ฐ ์คํ์ ์ค๋จํ๋ฉด ์ ์ฒด ์ด๋ฒคํธ ๋ฃจํ๊ฐ ์ผ์ ์ค์ง๋ฉ๋๋ค. ์ด๋ ๋์ ์คํ์ ์ ํํ๊ฒ ๋ฐ์ํ์ง ์๊ธฐ ๋๋ฌธ์ ์คํด๋ฅผ ๋ถ๋ฌ์ผ์ผํฌ ์ ์์ต๋๋ค.
pdb ์ฌ์ฉ ๋ฐฉ๋ฒ:
- ์คํ์ ์ค๋จํ๊ณ ์ถ์ ๊ณณ์
import pdb; pdb.set_trace()๋ฅผ ์ฝ์ ํ์ธ์. - ๋๋ฒ๊ฑฐ๊ฐ ์ค๋จ๋๋ฉด ๋ณ์๋ฅผ ๊ฒ์ฌํ๊ณ , ์ฝ๋๋ฅผ ํ ๋จ๊ณ์ฉ ์คํํ๋ฉฐ(
await์์๋ ์คํ ์คํ์ด ๊น๋ค๋ก์ธ ์ ์์), ํํ์์ ํ๊ฐํ ์ ์์ต๋๋ค. await์๋ก ์คํ ์ค๋ฒํ๋ฉด ๋๊ธฐ ์ค์ธ ์ฝ๋ฃจํด์ด ์๋ฃ๋ ๋๊น์ง ๋๋ฒ๊ฑฐ๊ฐ ์ผ์ ์ค์ง๋์ด, ๊ทธ ์๊ฐ์๋ ์์ฐจ์ ์ผ๋ก ์คํ๋๋ ๊ฒ์ฒ๋ผ ๋ณด์ธ๋ค๋ ์ ์ ์ ์ํ์ธ์.
breakpoint()๋ฅผ ์ฌ์ฉํ ๊ณ ๊ธ ๋๋ฒ๊น
(Python 3.7+):
๋ด์ฅ ํจ์์ธ breakpoint()๋ ๋ ์ ์ฐํ๋ฉฐ ๋ค๋ฅธ ๋๋ฒ๊ฑฐ๋ฅผ ์ฌ์ฉํ๋๋ก ๊ตฌ์ฑํ ์ ์์ต๋๋ค. PYTHONBREAKPOINT ํ๊ฒฝ ๋ณ์๋ฅผ ์ค์ ํ ์ ์์ต๋๋ค.
AsyncIO๋ฅผ ์ํ ๋๋ฒ๊น ๋๊ตฌ:
์ผ๋ถ IDE(PyCharm ๋ฑ)๋ ๋น๋๊ธฐ ์ฝ๋ ๋๋ฒ๊น ์ ๋ํ ํฅ์๋ ์ง์์ ์ ๊ณตํ์ฌ ์ฝ๋ฃจํด ์ํ์ ๋ํ ์๊ฐ์ ๋จ์์ ๋ ์ฌ์ด ์คํ ์คํ์ ์ ๊ณตํฉ๋๋ค.
3. AsyncIO์ ์คํ ํธ๋ ์ด์ค ์ดํดํ๊ธฐ
Asyncio ์คํ ํธ๋ ์ด์ค๋ ์ด๋ฒคํธ ๋ฃจํ์ ํน์ฑ ๋๋ฌธ์ ๋๋๋ก ๋ณต์กํ ์ ์์ต๋๋ค. ์์ธ๋ ์ฝ๋ฃจํด ์ฝ๋์ ํจ๊ป ์ด๋ฒคํธ ๋ฃจํ์ ๋ด๋ถ ์๋๊ณผ ๊ด๋ จ๋ ํ๋ ์์ ๋ณด์ฌ์ค ์ ์์ต๋๋ค.
๋น๋๊ธฐ ์คํ ํธ๋ ์ด์ค ์ฝ๊ธฐ ํ:
- ์์ ์ ์ฝ๋์ ์ง์คํ๊ธฐ: ์ ํ๋ฆฌ์ผ์ด์ ์ฝ๋์์ ๋น๋กฏ๋ ํ๋ ์์ ์๋ณํ์ธ์. ์ด๋ค์ ๋ณดํต ํธ๋ ์ด์ค์ ์๋จ์ ๋ํ๋ฉ๋๋ค.
- ์์ธ ์ถ์ ํ๊ธฐ: ์์ธ๊ฐ ์ฒ์ ๋ฐ์ํ ์์น์
awaitํธ์ถ์ ํตํด ์ด๋ป๊ฒ ์ ํ๋์๋์ง ์ฐพ์๋ณด์ธ์. asyncio.run_coroutine_threadsafe: ์ค๋ ๋ ๊ฐ ๋๋ฒ๊น ์, ์ฝ๋ฃจํด์ ์ค๋ ๋ ๊ฐ์ ์ ๋ฌํ ๋ ์์ธ๊ฐ ์ด๋ป๊ฒ ์ฒ๋ฆฌ๋๋์ง ์ธ์งํ๊ณ ์์ด์ผ ํฉ๋๋ค.
4. asyncio ๋๋ฒ๊ทธ ๋ชจ๋ ์ฌ์ฉํ๊ธฐ
asyncio์๋ ์ผ๋ฐ์ ์ธ ํ๋ก๊ทธ๋๋ฐ ์ค๋ฅ๋ฅผ ์ก๋ ๋ฐ ๋์์ด ๋๋ ๊ฒ์ฌ์ ๋ก๊น
์ ์ถ๊ฐํ๋ ๋ด์ฅ ๋๋ฒ๊ทธ ๋ชจ๋๊ฐ ์์ต๋๋ค. asyncio.run()์ debug=True๋ฅผ ์ ๋ฌํ๊ฑฐ๋ PYTHONASYNCIODEBUG ํ๊ฒฝ ๋ณ์๋ฅผ ์ค์ ํ์ฌ ํ์ฑํํ์ธ์.
import asyncio
async def potentially_buggy_coro():
# This is a simplified example. Debug mode catches more subtle issues.
await asyncio.sleep(0.1)
# Example: If this were to accidentally block the loop
async def main():
print("Running with asyncio debug mode enabled.")
await potentially_buggy_coro()
if __name__ == "__main__":
asyncio.run(main(), debug=True)
๋๋ฒ๊ทธ ๋ชจ๋๊ฐ ์ก์๋ด๋ ๊ฒ๋ค:
- ์ด๋ฒคํธ ๋ฃจํ์์์ ๋ธ๋กํน ํธ์ถ.
- await๋์ง ์์ ์ฝ๋ฃจํด.
- ์ฝ๋ฐฑ์์ ์ฒ๋ฆฌ๋์ง ์์ ์์ธ.
- ํ์คํฌ ์ทจ์์ ๋ถ์ ์ ํ ์ฌ์ฉ.
๋๋ฒ๊ทธ ๋ชจ๋์ ์ถ๋ ฅ์ ์ฅํฉํ ์ ์์ง๋ง, ์ด๋ฒคํธ ๋ฃจํ์ ์๋๊ณผ asyncio API์ ์ ์ฌ์ ์ค์ฉ์ ๋ํ ๊ท์คํ ํต์ฐฐ๋ ฅ์ ์ ๊ณตํฉ๋๋ค.
5. ๊ณ ๊ธ ๋น๋๊ธฐ ๋๋ฒ๊น ์ ์ํ ๋๊ตฌ
ํ์ค ๋๊ตฌ ์ธ์๋ ํนํ๋ ๊ธฐ์ ์ด ๋๋ฒ๊น ์ ๋์์ด ๋ ์ ์์ต๋๋ค:
aiomonitor: ์คํ ์ค์ธasyncio์ ํ๋ฆฌ์ผ์ด์ ์ ๋ํ ๋ผ์ด๋ธ ๊ฒ์ฌ ์ธํฐํ์ด์ค๋ฅผ ์ ๊ณตํ๋ ๊ฐ๋ ฅํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก, ์คํ์ ์ค๋จํ์ง ์๋ ๋๋ฒ๊ฑฐ์ ์ ์ฌํฉ๋๋ค. ์คํ ์ค์ธ ํ์คํฌ, ์ฝ๋ฐฑ ๋ฐ ์ด๋ฒคํธ ๋ฃจํ ์ํ๋ฅผ ๊ฒ์ฌํ ์ ์์ต๋๋ค.- ์ฌ์ฉ์ ์ ์ ํ์คํฌ ํฉํ ๋ฆฌ: ๋ณต์กํ ์๋๋ฆฌ์ค์ ๊ฒฝ์ฐ, ์ฌ์ฉ์ ์ ์ ํ์คํฌ ํฉํ ๋ฆฌ๋ฅผ ๋ง๋ค์ด ์ ํ๋ฆฌ์ผ์ด์ ์์ ์์ฑ๋๋ ๋ชจ๋ ํ์คํฌ์ ๊ณ์ธก์ด๋ ๋ก๊น ์ ์ถ๊ฐํ ์ ์์ต๋๋ค.
- ํ๋กํ์ผ๋ง:
cProfile๊ณผ ๊ฐ์ ๋๊ตฌ๋ ์ข ์ข ๋์์ฑ ๋ฌธ์ ์ ๊ด๋ จ๋ ์ฑ๋ฅ ๋ณ๋ชฉ ํ์์ ์๋ณํ๋ ๋ฐ ๋์์ด ๋ ์ ์์ต๋๋ค.
AsyncIO ๊ฐ๋ฐ์์ ๊ธ๋ก๋ฒ ๊ณ ๋ ค์ฌํญ ์ฒ๋ฆฌํ๊ธฐ
๊ธ๋ก๋ฒ ์ฌ์ฉ์๋ฅผ ์ํ ๋น๋๊ธฐ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ฐ๋ฐํ๋ ๊ฒ์ ํน์ ํ ๊ณผ์ ๋ฅผ ์ ๊ธฐํ๋ฉฐ ์ ์คํ ๊ณ ๋ ค๊ฐ ํ์ํฉ๋๋ค:
- ์๊ฐ๋: ์๊ฐ ๋ฏผ๊ฐํ ์์ (์ค์ผ์ค๋ง, ๋ก๊น , ํ์์์)์ด ๋ค๋ฅธ ์๊ฐ๋์์ ์ด๋ป๊ฒ ๋์ํ๋์ง ์ ์ํ์ธ์. ๋ด๋ถ ํ์์คํฌํ์๋ ์ผ๊ด๋๊ฒ UTC๋ฅผ ์ฌ์ฉํ์ธ์.
- ๋คํธ์ํฌ ์ง์ฐ ๋ฐ ์ ๋ขฐ์ฑ: ๋น๋๊ธฐ ํ๋ก๊ทธ๋๋ฐ์ ์ข
์ข
์ง์ฐ ์๊ฐ์ ์ํํ๊ธฐ ์ํด ์ฌ์ฉ๋์ง๋ง, ๋งค์ฐ ๊ฐ๋ณ์ ์ด๊ฑฐ๋ ์ ๋ขฐํ ์ ์๋ ๋คํธ์ํฌ๋ ๊ฒฌ๊ณ ํ ์ฌ์๋ ๋ฉ์ปค๋์ฆ๊ณผ ์ฐ์ํ ์ฑ๋ฅ ์ ํ๊ฐ ํ์ํฉ๋๋ค. ์๋ฎฌ๋ ์ด์
๋ ๋คํธ์ํฌ ์กฐ๊ฑด(์:
toxiproxy์ ๊ฐ์ ๋๊ตฌ ์ฌ์ฉ) ํ์์ ์ค๋ฅ ์ฒ๋ฆฌ๋ฅผ ํ ์คํธํ์ธ์. - ๊ตญ์ ํ(i18n) ๋ฐ ํ์งํ(l10n): ์ค๋ฅ ๋ฉ์์ง๋ ์ฝ๊ฒ ๋ฒ์ญ๋ ์ ์๋๋ก ์ค๊ณ๋์ด์ผ ํฉ๋๋ค. ์ค๋ฅ ๋ฉ์์ง์ ๊ตญ๊ฐ๋ณ ํ์์ด๋ ๋ฌธํ์ ์ฐธ์กฐ๋ฅผ ํฌํจํ์ง ๋ง์ธ์.
- ๋ฆฌ์์ค ์ ํ: ์ง์ญ๋ง๋ค ๋์ญํญ์ด๋ ์ฒ๋ฆฌ ๋ฅ๋ ฅ์ด ๋ค๋ฅผ ์ ์์ต๋๋ค. ํ์์์๊ณผ ๋ฆฌ์์ค ๊ฒฝ์์ ์ฐ์ํ๊ฒ ์ฒ๋ฆฌํ๋๋ก ์ค๊ณํ๋ ๊ฒ์ด ํต์ฌ์ ๋๋ค.
- ๋ฐ์ดํฐ ์ผ๊ด์ฑ: ๋ถ์ฐ ๋น๋๊ธฐ ์์คํ ์ ๋ค๋ฃฐ ๋, ๋ค๋ฅธ ์ง๋ฆฌ์ ์์น ๊ฐ์ ๋ฐ์ดํฐ ์ผ๊ด์ฑ์ ๋ณด์ฅํ๋ ๊ฒ์ ์ด๋ ค์ธ ์ ์์ต๋๋ค.
์์ : asyncio.wait_for๋ฅผ ์ฌ์ฉํ ๊ธ๋ก๋ฒ ํ์์์
asyncio.wait_for๋ ํ์คํฌ๊ฐ ๋ฌดํ์ ์คํ๋๋ ๊ฒ์ ๋ฐฉ์งํ๋ ๋ฐ ํ์์ ์ด๋ฉฐ, ์ด๋ ์ ์ธ๊ณ ์ฌ์ฉ์์๊ฒ ์๋น์ค๋ฅผ ์ ๊ณตํ๋ ์ ํ๋ฆฌ์ผ์ด์
์ ๋งค์ฐ ์ค์ํฉ๋๋ค.
import asyncio
import time
async def long_running_task(duration):
print(f"Starting task that takes {duration} seconds.")
await asyncio.sleep(duration)
print("Task finished naturally.")
return "Task Completed"
async def main():
print(f"Current time: {time.strftime('%X')}")
try:
# Set a global timeout for all operations
result = await asyncio.wait_for(long_running_task(5), timeout=3.0)
print(f"Operation successful: {result}")
except asyncio.TimeoutError:
print(f"Operation timed out after 3 seconds!")
except Exception as e:
print(f"An unexpected error occurred: {e}")
print(f"Current time: {time.strftime('%X')}")
if __name__ == "__main__":
asyncio.run(main())
์ค๋ช :
asyncio.wait_for๋ awaitable(์ฌ๊ธฐ์๋long_running_task)์ ๊ฐ์ธ๊ณ , awaitable์ด ์ง์ ๋timeout๋ด์ ์๋ฃ๋์ง ์์ผ๋ฉดasyncio.TimeoutError๋ฅผ ๋ฐ์์ํต๋๋ค.- ์ด๋ ์ฌ์ฉ์ ๋๋ฉด ์ ํ๋ฆฌ์ผ์ด์ ์ด ์๊ธฐ์ ์ ํ ์๋ต์ ์ ๊ณตํ๊ณ ๋ฆฌ์์ค ๊ณ ๊ฐ์ ๋ฐฉ์งํ๋ ๋ฐ ํ์์ ์ ๋๋ค.
AsyncIO ์ค๋ฅ ์ฒ๋ฆฌ ๋ฐ ๋๋ฒ๊น ์ ์ํ ๋ชจ๋ฒ ์ฌ๋ก
๊ธ๋ก๋ฒ ์ฌ์ฉ์๋ฅผ ์ํ ๊ฒฌ๊ณ ํ๊ณ ์ ์ง๋ณด์ ๊ฐ๋ฅํ ๋น๋๊ธฐ ํ์ด์ฌ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์ถํ๋ ค๋ฉด ๋ค์ ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ์ฑํํ์ธ์:
- ์์ธ๋ฅผ ๋ช
์์ ์ผ๋ก ์ฒ๋ฆฌํ๊ธฐ: ๊ด๋ฒ์ํ
except Exception๋์ ๊ฐ๋ฅํ๋ฉด ํน์ ์์ธ๋ฅผ ์ก์ผ์ธ์. ์ด๋ ๊ฒ ํ๋ฉด ์ฝ๋๊ฐ ๋ ๋ช ํํด์ง๊ณ ์์์น ๋ชปํ ์ค๋ฅ๋ฅผ ๊ฐ๋ฆด ๊ฐ๋ฅ์ฑ์ด ์ค์ด๋ญ๋๋ค. asyncio.gather(..., return_exceptions=True)ํ๋ช ํ๊ฒ ์ฌ์ฉํ๊ธฐ: ๋ชจ๋ ํ์คํฌ๊ฐ ์๋ฃ๋ฅผ ์๋ํ๊ฒ ํ๋ ค๋ ์๋๋ฆฌ์ค์ ํ๋ฅญํ์ง๋ง, ํผํฉ๋ ๊ฒฐ๊ณผ(์ฑ๊ณต๊ณผ ์คํจ)๋ฅผ ์ฒ๋ฆฌํ ์ค๋น๋ฅผ ํด์ผ ํฉ๋๋ค.- ๊ฒฌ๊ณ ํ ์ฌ์๋ ๋ก์ง ๊ตฌํํ๊ธฐ: ์ผ์์ ์ธ ์คํจ์ ์ทจ์ฝํ ์์
(์: ๋คํธ์ํฌ ํธ์ถ)์ ๊ฒฝ์ฐ, ์ฆ์ ์คํจํ๋ ๋์ ๋ฐฑ์คํ ์ง์ฐ์ ํฌํจํ ์ค๋งํธํ ์ฌ์๋ ์ ๋ต์ ๊ตฌํํ์ธ์.
backoff์ ๊ฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ๋งค์ฐ ์ ์ฉํ ์ ์์ต๋๋ค. - ๋ก๊น ์ค์ํํ๊ธฐ: ๋ก๊น ๊ตฌ์ฑ์ด ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ฐ์ ๊ฑธ์ณ ์ผ๊ด๋๊ณ ๊ธ๋ก๋ฒ ํ์ด ๋๋ฒ๊น ํ๊ธฐ ์ฝ๋๋ก ํ์ธ์. ๋ ์ฌ์ด ๋ถ์์ ์ํด ๊ตฌ์กฐํ๋ ๋ก๊น ์ ์ฌ์ฉํ์ธ์.
- ๊ด์ฐฐ ๊ฐ๋ฅ์ฑ์ ๊ณ ๋ คํ์ฌ ์ค๊ณํ๊ธฐ: ๋ก๊น ์ธ์๋ ํ๋ก๋์ ํ๊ฒฝ์์ ์ ํ๋ฆฌ์ผ์ด์ ๋์์ ์ดํดํ๊ธฐ ์ํด ๋ฉํธ๋ฆญ๊ณผ ์ถ์ ์ ๊ณ ๋ คํ์ธ์. Prometheus, Grafana, ๋ถ์ฐ ์ถ์ ์์คํ (์: Jaeger, OpenTelemetry)๊ณผ ๊ฐ์ ๋๊ตฌ๋ ๋งค์ฐ ์ค์ํฉ๋๋ค.
- ์ฒ ์ ํ๊ฒ ํ
์คํธํ๊ธฐ: ๋น๋๊ธฐ ์ฝ๋์ ์ค๋ฅ ์กฐ๊ฑด์ ๊ตฌ์ฒด์ ์ผ๋ก ๋์์ผ๋ก ํ๋ ๋จ์ ๋ฐ ํตํฉ ํ
์คํธ๋ฅผ ์์ฑํ์ธ์.
pytest-asyncio์ ๊ฐ์ ๋๊ตฌ๋ฅผ ์ฌ์ฉํ์ธ์. ํ ์คํธ์์ ๋คํธ์ํฌ ์คํจ, ํ์์์ ๋ฐ ์ทจ์๋ฅผ ์๋ฎฌ๋ ์ด์ ํ์ธ์. - ๋์์ฑ ๋ชจ๋ธ ์ดํดํ๊ธฐ: ๋จ์ผ ์ค๋ ๋ ๋ด์์
asyncio๋ฅผ ์ฌ์ฉํ๋์ง, ์ฌ๋ฌ ์ค๋ ๋(run_in_executor๋ฅผ ํตํด) ๋๋ ์ฌ๋ฌ ํ๋ก์ธ์ค์ ๊ฑธ์ณ ์ฌ์ฉํ๋์ง ๋ช ํํ ํ์ธ์. ์ด๋ ์ค๋ฅ ์ ํ ๋ฐฉ์๊ณผ ๋๋ฒ๊น ์๋ ๋ฐฉ์์ ์ํฅ์ ๋ฏธ์นฉ๋๋ค. - ๊ฐ์ ๋ฌธ์ํํ๊ธฐ: ํนํ ๊ธ๋ก๋ฒ ์ฌ์ฉ์๋ฅผ ์ํด ๊ตฌ์ถํ ๋ ๋คํธ์ํฌ ์ ๋ขฐ์ฑ, ์๋น์ค ๊ฐ์ฉ์ฑ ๋๋ ์์ ์ง์ฐ ์๊ฐ์ ๋ํ ๊ฐ์ ์ ๋ช ํํ๊ฒ ๋ฌธ์ํํ์ธ์.
๊ฒฐ๋ก
asyncio ์ฝ๋ฃจํด์ ๋๋ฒ๊น
๋ฐ ์ค๋ฅ ์ฒ๋ฆฌ๋ ํ๋์ ์ด๊ณ ๊ณ ์ฑ๋ฅ์ธ ์ ํ๋ฆฌ์ผ์ด์
์ ๊ตฌ์ถํ๋ ๋ชจ๋ ํ์ด์ฌ ๊ฐ๋ฐ์์๊ฒ ์ค์ํ ๊ธฐ์ ์
๋๋ค. ๋น๋๊ธฐ ์คํ์ ๋ฏธ๋ฌํ ์ฐจ์ด๋ฅผ ์ดํดํ๊ณ , ํ์ด์ฌ์ ๊ฒฌ๊ณ ํ ์์ธ ์ฒ๋ฆฌ๋ฅผ ํ์ฉํ๋ฉฐ, ์ ๋ต์ ์ธ ๋ก๊น
๋ฐ ๋๋ฒ๊น
๋๊ตฌ๋ฅผ ์ฌ์ฉํจ์ผ๋ก์จ, ์ ์ธ๊ณ์ ์ผ๋ก ํ๋ ฅ ์๊ณ ์ ๋ขฐํ ์ ์์ผ๋ฉฐ ์ฑ๋ฅ์ด ๋ฐ์ด๋ ์ ํ๋ฆฌ์ผ์ด์
์ ๊ตฌ์ถํ ์ ์์ต๋๋ค.
try...except์ ํ์ ๋ฐ์๋ค์ด๊ณ , asyncio.CancelledError์ asyncio.TimeoutError๋ฅผ ๋ง์คํฐํ๋ฉฐ, ํญ์ ๊ธ๋ก๋ฒ ์ฌ์ฉ์๋ฅผ ์ผ๋์ ๋์ธ์. ๊พธ์คํ ์ฐ์ต๊ณผ ์ฌ๋ฐ๋ฅธ ์ ๋ต์ ํตํด ๋น๋๊ธฐ ํ๋ก๊ทธ๋๋ฐ์ ๋ณต์ก์ฑ์ ํด๊ฒฐํ๊ณ ์ ์ธ๊ณ์ ๋ฐ์ด๋ ์ํํธ์จ์ด๋ฅผ ์ ๊ณตํ ์ ์์ต๋๋ค.